import 'dart:async';

import 'package:built_collection/built_collection.dart';
import 'package:dartz/dartz.dart';
import 'package:equatable/equatable.dart';
import 'package:mobile_app.core/core/domain/entities/learning_content/collection_list_item/collection_list_item.dart';
import 'package:mobile_app.core/core/domain/entities/learning_content/lexical_item/lexical_item.dart';
import 'package:mobile_app.core/core/domain/repositories/learning_content_repository/repository.dart';
import 'package:mobile_app.home.collections/single_custom_collection_folder_page/domain/entities/collection_folder_deletion_mode.dart';
import 'package:mobile_app.home.collections/single_custom_collection_folder_page/domain/helpers/get_all_collection_lexical_item_ids/helper.dart';
import 'package:mobile_app.home.collections.core/core/domain/helpers/apply_custom_collection_list_item_deletion/helper.dart';
import 'package:mobile_app.home.collections.core/core/domain/helpers/filter_custom_collection_exclusive_lexical_item_ids/helper.dart';
import 'package:mobile_app.home.collections.core/core/domain/helpers/filter_custom_lexical_item_ids/helper.dart';
import 'package:mobile_app.home.core/core/domain/helpers/apply_all_collection_list_item_nonexistent_lexical_item_removal/helper.dart';

part 'failures.dart';

part 'result.dart';

abstract class CompleteCollectionFolderDeletion {
  Either<CollectionFolderDeletionCompletionFailure, CollectionFolderDeletionCompletionResult> call({
    required CustomCollectionFolder collectionFolder,
    required CollectionFolderDeletionMode deletionMode,
    required BuiltMap<String, LexicalItem> lexicalItemMap,
    required BuiltList<CollectionListItem> collectionListItems,
  });
}

class CompleteCollectionFolderDeletionImpl implements CompleteCollectionFolderDeletion {
  const CompleteCollectionFolderDeletionImpl({
    required ApplyCustomCollectionListItemDeletion applyCustomCollectionListItemDeletion,
    required GetAllCollectionLexicalItemIds getAllCollectionLexicalItemIds,
    required FilterCustomCollectionExclusiveLexicalItemIds
        filterCustomCollectionExclusiveLexicalItemIds,
    required FilterCustomLexicalItemIds filterCustomLexicalItemIds,
    required ApplyAllCollectionListItemNonexistentLexicalItemRemoval applyAllCollectionListItemNonexistentLexicalItemRemoval,
    required LearningContentRepository learningContentRepository,
  })  : _applyCustomCollectionListItemDeletion = applyCustomCollectionListItemDeletion,
        _getAllCollectionLexicalItemIds = getAllCollectionLexicalItemIds,
        _filterCustomCollectionExclusiveLexicalItemIds =
            filterCustomCollectionExclusiveLexicalItemIds,
        _filterCustomLexicalItemIds = filterCustomLexicalItemIds,
        _applyAllCollectionListItemNonexistentLexicalItemRemoval = applyAllCollectionListItemNonexistentLexicalItemRemoval,
        _learningContentRepository = learningContentRepository;

  final ApplyCustomCollectionListItemDeletion _applyCustomCollectionListItemDeletion;
  final GetAllCollectionLexicalItemIds _getAllCollectionLexicalItemIds;
  final FilterCustomCollectionExclusiveLexicalItemIds
      _filterCustomCollectionExclusiveLexicalItemIds;
  final FilterCustomLexicalItemIds _filterCustomLexicalItemIds;
  final ApplyAllCollectionListItemNonexistentLexicalItemRemoval _applyAllCollectionListItemNonexistentLexicalItemRemoval;

  final LearningContentRepository _learningContentRepository;

  @override
  Either<CollectionFolderDeletionCompletionFailure, CollectionFolderDeletionCompletionResult> call({
    required CustomCollectionFolder collectionFolder,
    required CollectionFolderDeletionMode deletionMode,
    required BuiltMap<String, LexicalItem> lexicalItemMap,
    required BuiltList<CollectionListItem> collectionListItems,
  }) {
    if (deletionMode == CollectionFolderDeletionMode.collectionFolder) {
      final updatedCollectionListItems = _applyCustomCollectionListItemDeletion(
        customCollectionListItemId: collectionFolder.id,
        collectionListItems: collectionListItems,
      );

      final result = CollectionFolderDeletionCompletionResult(
        lexicalItemMap: lexicalItemMap,
        collectionListItems: updatedCollectionListItems,
      );

      unawaited(_learningContentRepository.saveCollectionListItems(
        collectionListItems: updatedCollectionListItems,
      ));

      return right(result);
    }

    final collectionFolderLexicalItemIds = _getAllCollectionLexicalItemIds(
      collections: collectionFolder.collections,
    );

    final collectionFolderCustomLexicalItemIds = _filterCustomLexicalItemIds(
      lexicalItemIds: collectionFolderLexicalItemIds,
      lexicalItemMap: lexicalItemMap,
    );

    final collectionFolderCollectionIds = collectionFolder.collections.map((collection) {
      return collection.id;
    }).toBuiltSet();

    final collectionFolderExclusiveCustomLexicalItemIds =
        _filterCustomCollectionExclusiveLexicalItemIds(
      customLexicalItemIds: collectionFolderCustomLexicalItemIds.toBuiltSet(),
      exclusiveCustomLexicalItemCollectionIds: collectionFolderCollectionIds,
      collectionListItems: collectionListItems,
    );

    late final Iterable<String> toBeDeletedLexicalItemIds;

    if (deletionMode == CollectionFolderDeletionMode.collectionFolderAndLexicalItems) {
      if (collectionFolderCustomLexicalItemIds.length !=
          collectionFolderExclusiveCustomLexicalItemIds.length) {
        const failure = CustomLexicalItemNotExclusiveCollectionFolderDeletionCompletionFailure();
        return left(failure);
      }

      toBeDeletedLexicalItemIds = collectionFolderCustomLexicalItemIds;
    } else if (deletionMode ==
        CollectionFolderDeletionMode.collectionFolderAndExclusiveLexicalItems) {
      toBeDeletedLexicalItemIds = collectionFolderExclusiveCustomLexicalItemIds;
    } else if (deletionMode == CollectionFolderDeletionMode.collectionFolderAndAllLexicalItems) {
      toBeDeletedLexicalItemIds = collectionFolderCustomLexicalItemIds;
    }

    final updatedLexicalItemMap = lexicalItemMap.rebuild((lexicalItemMap) {
      for (final lexicalItemId in toBeDeletedLexicalItemIds) {
        lexicalItemMap.remove(lexicalItemId);
      }
    });

    var updatedCollectionListItems = _applyCustomCollectionListItemDeletion(
      customCollectionListItemId: collectionFolder.id,
      collectionListItems: collectionListItems,
    );

    updatedCollectionListItems = _applyAllCollectionListItemNonexistentLexicalItemRemoval(
      lexicalItemMap: updatedLexicalItemMap,
      collectionListItems: updatedCollectionListItems,
    );

    final result = CollectionFolderDeletionCompletionResult(
      lexicalItemMap: updatedLexicalItemMap,
      collectionListItems: updatedCollectionListItems,
    );

    unawaited(Future.wait([
      _learningContentRepository.saveLexicalItems(
        lexicalItems: updatedLexicalItemMap.values.toBuiltList(),
      ),
      _learningContentRepository.saveCollectionListItems(
        collectionListItems: updatedCollectionListItems,
      ),
    ]));

    return right(result);
  }
}
